package org.swim.core.manager;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import net.sf.json.JsonConfig;

import org.swim.core.entities.Collaboration;
import org.swim.core.entities.Feedback;
import org.swim.core.entities.Message;
import org.swim.core.entities.User;
import org.swim.local.manager.CollaborationManagerLocal;
import org.swim.remote.entities.ICollaboration;
import org.swim.remote.entities.ICollaboration.Status;
import org.swim.remote.entities.ICollaboration.Visibility;
import org.swim.remote.entities.IFeedback;
import org.swim.remote.entities.IMessage;
import org.swim.remote.entities.INotification.NotificationStatus;
import org.swim.remote.exceptions.CollaborationException;
import org.swim.remote.exceptions.SwimException;
import org.swim.remote.exceptions.SwimException.Severity;
import org.swim.remote.exceptions.TokenException;
import org.swim.remote.manager.CollaborationManagerRemote;

@Stateless
public class CollaborationManager implements CollaborationManagerRemote,
		CollaborationManagerLocal {

	private static JsonConfig COLLABORATION_JSON_CFG;
	private static JsonConfig MESSAGE_JSON_CFG;
	private static JsonConfig FEEDBACK_JSON_CFG;

	static {
		COLLABORATION_JSON_CFG = new JsonConfig();
		COLLABORATION_JSON_CFG.setRootClass(Collaboration.class);

		MESSAGE_JSON_CFG = new JsonConfig();
		MESSAGE_JSON_CFG.setRootClass(Message.class);

		FEEDBACK_JSON_CFG = new JsonConfig();
		FEEDBACK_JSON_CFG.setRootClass(Feedback.class);
	}

	@PersistenceContext(unitName = "swimds")
	private EntityManager em;

	public ICollaboration post(JSONObject json) {
		Collaboration collaboration = (Collaboration) JSONSerializer.toJava(
				json, COLLABORATION_JSON_CFG);
		em.persist(collaboration);
		return collaboration;
	}

	public ICollaboration delete(Integer id) {
		Collaboration collaboration = em.find(Collaboration.class, id);
		em.remove(collaboration);
		return collaboration;
	}

	public ICollaboration put(JSONObject json) {
		Collaboration collaboration = (Collaboration) JSONSerializer.toJava(
				json, COLLABORATION_JSON_CFG);
		em.merge(collaboration);

		return collaboration;
	}

	public ICollaboration get(Integer id) throws SwimException {
		Query q = em.createQuery("SELECT c FROM Collaboration c WHERE c.id = '"
				+ id + "'");

		if (q.getResultList().size() != 1)
			throw new SwimException("COLLABOATION DOESN'T EXIST",
					Severity.ERROR);

		return (Collaboration) q.getSingleResult();
	}

	@SuppressWarnings("unchecked")
	public List<ICollaboration> getAll() {
		Query q = em.createQuery("SELECT c FROM Collaboration c");
		return q.getResultList();
	}

	public ICollaboration createBaseCollaboration(JSONObject object)
			throws NamingException, SwimException {

		User senderUser = SwimManager.getUml().getUnregisteredUser(
				object.getString("senderEmail"));

		Integer receiverId = object.getJSONObject("collaboration").getInt(
				"receiverId");
		User receiverUser = (User) SwimManager.getUml().get(receiverId);

		String titleCollaboration = object.getJSONObject("collaboration")
				.getString("title");

		Collaboration collaboration = new Collaboration();
		collaboration.setTitle(titleCollaboration);
		collaboration.setUserBySenderId(senderUser);
		collaboration.setUserByReceiverId(receiverUser);

		em.persist(collaboration);

		String messageText = object.getJSONObject("message").getString(
				"message");

		Message message = new Message();
		message.setCollaboration(collaboration);
		message.setMessage(messageText);
		message.setUserBySenderId(senderUser);
		message.setUserByReceiverId(receiverUser);

		em.persist(message);
		em.refresh(collaboration);

		return collaboration;
	}

	public ICollaboration createCollaboration(JSONObject object)
			throws SwimException, NamingException {

		String tokenUser = object.getString("token");
		Integer senderId = UserLogged.getUserLogged()
				.checkUserLogged(tokenUser);

		User senderUser = (User) SwimManager.getUml().get(senderId);

		Integer receiverId = object.getJSONObject("collaboration").getInt(
				"receiverId");
		User receiverUser = (User) SwimManager.getUml().get(receiverId);

		String titleCollaboration = object.getJSONObject("collaboration")
				.getString("title");

		Visibility senderVisibility = Visibility.valueOf(object.getJSONObject(
				"collaboration").getString("senderVisibility"));

		Collaboration collaboration = new Collaboration();
		collaboration.setTitle(titleCollaboration);
		collaboration.setUserBySenderId(senderUser);
		collaboration.setUserByReceiverId(receiverUser);
		collaboration.setSenderVisibility(senderVisibility);

		em.persist(collaboration);

		String messageText = object.getJSONObject("message").getString(
				"message");

		Message message = new Message();
		message.setCollaboration(collaboration);
		message.setMessage(messageText);
		message.setUserBySenderId(senderUser);
		message.setUserByReceiverId(receiverUser);

		em.persist(message);
		em.refresh(collaboration);

		return collaboration;
	}

	public ICollaboration postFeedback(JSONObject object) throws SwimException,
			NamingException {
		String tokenUser = object.getString("token");
		Integer senderId = UserLogged.getUserLogged()
				.checkUserLogged(tokenUser);
		User senderUser = (User) SwimManager.getUml().get(senderId);

		Integer collaborationId = object.getJSONObject("feedback").getInt(
				"collaborationId");
		Collaboration collaboration = (Collaboration) get(collaborationId);

		if (collaboration.getStatus() != Status.COMPLETED) {
			throw new CollaborationException(
					"THE COLLABORATION MUST BE COMPLETED");
		}

		User receiverUser;

		if (collaboration.getUserByReceiverId().getId().compareTo(senderId) == 0) {
			receiverUser = collaboration.getUserBySenderId();
		} else
			receiverUser = collaboration.getUserByReceiverId();

		Query q = em
				.createQuery("SELECT fb FROM Feedback fb WHERE fb.userBySenderId = '"
						+ senderId
						+ "' and"
						+ " userByReceiverId = '"
						+ receiverUser.getId()
						+ "' and fb.collaboration = '"
						+ collaborationId + "'");
		if (!q.getResultList().isEmpty())
			throw new CollaborationException("THERE IS ALREADY A FEEDBACK");

		String comment = object.getJSONObject("feedback").getString("comment");
		Integer valuation = object.getJSONObject("feedback")
				.getInt("valuation");

		Feedback feedback = new Feedback();
		feedback.setCollaboration(collaboration);
		feedback.setUserBySenderId(senderUser);
		feedback.setUserByReceiverId(receiverUser);
		feedback.setComment(comment);
		feedback.setValuation(valuation);

		em.persist(feedback);

		collaboration.setSingleFeedback(feedback);

		return collaboration;
	}

	public ICollaboration deleteFeedback(JSONObject object)
			throws TokenException, CollaborationException {
		String tokenUser = object.getString("token");
		Integer senderId = UserLogged.getUserLogged()
				.checkUserLogged(tokenUser);

		Integer feedbackId = object.getInt("feedbackId");

		Query q = em.createQuery("SELECT fb FROM Feedback fb WHERE fb.id = '"
				+ feedbackId + "' and fb.userBySenderId = '" + senderId + "'");

		if (q.getResultList().size() != 1) {
			throw new CollaborationException(
					"THIS FEEDBACK DOESN'T EXIST OR YOU CAN'T DELETE IT");
		}

		Feedback feedback = (Feedback) q.getSingleResult();

		Collaboration collaboration = feedback.getCollaboration();

		em.remove(feedback);

		return collaboration;
	}

	public ICollaboration postMessage(JSONObject object) throws SwimException,
			NamingException {
		String tokenUser = object.getString("token");
		Integer senderId = UserLogged.getUserLogged()
				.checkUserLogged(tokenUser);
		User senderUser = (User) SwimManager.getUml().get(senderId);

		Integer collaborationId = object.getJSONObject("message").getInt(
				"collaborationId");
		Collaboration collaboration = (Collaboration) get(collaborationId);

		if (collaboration.getStatus() != Status.CONFIRMED) {
			throw new CollaborationException(
					"THE COLLABORATION IS NOT CONFIRMED");
		}

		User receiverUser;

		if (collaboration.getUserByReceiverId().getId().compareTo(senderId) == 0) {
			receiverUser = collaboration.getUserBySenderId();
		} else
			receiverUser = collaboration.getUserByReceiverId();

		String messageText = object.getJSONObject("message").getString(
				"message");
		
		if(messageText != null && messageText.equals(""))
			throw new CollaborationException("MESSAGE EMPTY");

		Message message = new Message();
		message.setCollaboration(collaboration);
		message.setMessage(messageText);

		message.setUserBySenderId(senderUser);
		message.setUserByReceiverId(receiverUser);

		em.persist(message);

		collaboration.setSingleMessage(message);
		em.refresh(collaboration);
		return collaboration;
	}

	public ICollaboration setStatusCollaboration(JSONObject object)
			throws TokenException, CollaborationException {
		String tokenUser = object.getString("token");

		Integer idUser = UserLogged.getUserLogged().checkUserLogged(tokenUser);

		Integer idCollaboration = object.getInt("collaborationId");

		Status status = Status
				.valueOf(object.getString("status").toUpperCase());

		
		//***********************//
		if (status == null || status.equals(Status.REQUESTED))
			throw new CollaborationException(
					"You can't set collaboration status REQUESTED");

		Collaboration collaboration = em.find(Collaboration.class,
				idCollaboration);
		
		User user = em.find(User.class, idUser);
		if(!collaboration.isMy(user))
			throw new CollaborationException(
					"You can't modified a not your collaboration");
		//***********************//
		
		// Status statusReq;
		// if (status != ICollaboration.Status.COMPLETED)
		// statusReq = ICollaboration.Status.REQUESTED;
		// else
		// statusReq = ICollaboration.Status.CONFIRMED;
		//
		// Query q = em
		// .createQuery("SELECT c FROM Collaboration c WHERE c.userByReceiverId = '"
		// + idUser
		// + "' and c.id = '"
		// + idCollaboration
		// + "' "
		// + "and c.status = '" + statusReq + "'");
		//
		// if (q.getResultList().size() == 0)
		// if (status != ICollaboration.Status.COMPLETED)
		// throw new CollaborationException(
		// "COLLABORATION'S REQUEST DOESN'T EXIST");
		// else
		// throw new CollaborationException(
		// "COLLABORATION'S CONFIRMED DOESN'T EXIST");
		// Collaboration collaboration = (Collaboration) q.getSingleResult();

		collaboration.setStatus(status);

		em.merge(collaboration);

		return collaboration;
	}

	@SuppressWarnings("unchecked")
	public List<ICollaboration> getMyCollaborations(JSONObject object)
			throws TokenException {
		String tokenUser = object.getString("token");

		Integer idUser = UserLogged.getUserLogged().checkUserLogged(tokenUser);

		Query q = em
				.createQuery("SELECT m FROM Message m WHERE (m.userByReceiverId = '"
						+ idUser
						+ "' or m.userBySenderId = '"
						+ idUser
						+ "') ORDER BY m.timestamp DESC");

		List<IMessage> messages = q.getResultList();
		List<ICollaboration> collaborations2 = new ArrayList<ICollaboration>();

		for (IMessage iMessage : messages) {
			if (!collaborations2.contains(iMessage.getCollaboration()))
				collaborations2.add(iMessage.getCollaboration());
		}

		return collaborations2;
	}

	public IMessage setStatusMessageNotification(JSONObject object)
			throws TokenException, CollaborationException {
		String tokenUser = object.getString("token");

		UserLogged.getUserLogged().checkUserLogged(tokenUser);

		Integer idMessage = object.getInt("id");
		NotificationStatus notificationStatus = NotificationStatus
				.valueOf(object.getString("status"));
		//*********************************//
		Message message = em.find(Message.class, idMessage);
		
		message.setNotificationStatus(notificationStatus);
		em.merge(message);
		//*********************************//
		// Query q = em.createQuery("SELECT m FROM Message m WHERE m.id = '"
		// + idMessage + "' and f.notificationStatus = '"
		// + NotificationStatus.UNREAD + "'");
		//
		// if (q.getResultList().size() != 1) {
		// throw new CollaborationException("MESSAGE DATA ERROR");
		// }
		//
		// NotificationStatus notificationStatus = NotificationStatus
		// .valueOf(object.getString("status"));
		//
		// Message message = (Message) q.getSingleResult();
		//
		// message.setNotificationStatus(notificationStatus);
		//
		// em.merge(message);
		//
		// em.refresh(message.getCollaboration());

		return message;
	}

	public IFeedback setStatusFeedbackNotification(JSONObject object)
			throws TokenException, CollaborationException {
		String tokenUser = object.getString("token");

		UserLogged.getUserLogged().checkUserLogged(tokenUser);

		Integer idFeedback = object.getInt("id");
		NotificationStatus notificationStatus = NotificationStatus
				.valueOf(object.getString("status"));
		//************************************//
		Feedback feedback = em.find(Feedback.class, idFeedback);
		feedback.setNotificationStatus(notificationStatus);
		em.merge(feedback);
		
		//************************************//
		
		// Query q = em.createQuery("SELECT f FROM Feedback f WHERE f.id = '"
		// + idFeedback + "' and f.notificationStatus = '"
		// + NotificationStatus.UNREAD + "'");
		//
		// if (q.getResultList().size() != 1) {
		// throw new CollaborationException("FEEDBACK DATA ERROR");
		// }
		//
		// NotificationStatus notificationStatus = NotificationStatus
		// .valueOf(object.getString("status"));
		//
		// Feedback feedback = (Feedback) q.getSingleResult();
		//
		// feedback.setNotificationStatus(notificationStatus);
		//
		// em.merge(feedback);
		//
		// em.refresh(feedback.getCollaboration());

		return feedback;
	}

}
